package fr.xgouchet.wedding.client.presenter;

import java.util.Date;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.Widget;

import fr.xgouchet.wedding.client.event.FeedbackMessageEvent;
import fr.xgouchet.wedding.client.i18n.Constants;
import fr.xgouchet.wedding.client.i18n.Messages;
import fr.xgouchet.wedding.client.service.WebService;
import fr.xgouchet.wedding.shared.model.ProjectSettings;

/**
 * Displays the settings form
 * 
 * @author x.gouchet
 * 
 */
public class SettingsPresenter implements Presenter {

	/**
	 * Description of a Dashboard Display widget
	 */
	public interface Display {
		/**
		 * @return the Save button
		 */
		public HasClickHandlers getSaveButton();

		/**
		 * @return the Cancel button
		 */
		public HasClickHandlers getCancelButton();

		/**
		 * @param data
		 *            the current settings value
		 */
		public void displaySettings(ProjectSettings data);

		/**
		 * @return the new settings value
		 */
		public ProjectSettings getSettingsValue();

		/**
		 * @return The display as a Widget object
		 */
		public Widget asWidget();
	}

	/**
	 * Constructor
	 * 
	 * @param eventBus
	 *            the event bus
	 * @param display
	 *            the binded display to this presenter
	 */
	public SettingsPresenter(HandlerManager eventBus, Display display) {
		mEventBus = eventBus;
		mDisplay = display;
		bind();
	}

	/**
	 * @see Presenter#go(HasWidgets)
	 */
	public void go(HasWidgets container) {
		container.clear();
		container.add(mDisplay.asWidget());
		fetchSettings();
	}

	/**
	 * Binds the presenter's widget to the event bus
	 */
	private void bind() {
		mDisplay.getSaveButton().addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				doCheckAndSave();
			}
		});

		mDisplay.getCancelButton().addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				History.newItem("home");
			}
		});
	}

	/**
	 * Checks the user data and save if valid
	 */
	private void doCheckAndSave() {
		ProjectSettings newSettings = mDisplay.getSettingsValue();
		String msg = "";
		boolean valid = true;

		// check Date
		if ((newSettings.getWeddingDate() == null)
				|| (newSettings.getWeddingDate().before(new Date()))) {
			valid = false;
			msg += Messages.I18N.weddingDateInvalid() + " ";
		}

		// check newlyweds names
		if ((newSettings.getBrideFirstName().length() == 0)
				|| (newSettings.getGroomFirstName().length() == 0)) {
			valid = false;
			msg += Messages.I18N.settingsNamesInvalid() + " ";
		}

		// TODO check email validity (regex)

		// Check passwords
		if (!newSettings.getNewPsswd().equals(newSettings.getNewPsswdCheck())) {
			valid = false;
			msg += Messages.I18N.newPasswordsInvalid() + " ";
		}

		// TODO check password security (regex)

		if (!valid) {
			mEventBus.fireEvent(new FeedbackMessageEvent(msg, true));
			return;
		}

		WebService.saveSettings(newSettings,
				new AsyncCallback<ProjectSettings>() {
					public void onSuccess(ProjectSettings result) {
						History.newItem("home");
						mEventBus.fireEvent(new FeedbackMessageEvent(
								Messages.I18N.saveSuccessful(Constants.I18N
										.linkSettings()), false));
					}

					public void onFailure(Throwable caught) {
						mEventBus.fireEvent(new FeedbackMessageEvent(caught
								.getMessage(), true));
					}
				});
	}

	/**
	 * Fetch the current settings and send them to the display
	 */
	private void fetchSettings() {
		WebService.fetchSettings(new AsyncCallback<ProjectSettings>() {
			public void onSuccess(ProjectSettings result) {
				mDisplay.displaySettings(result);
			}

			public void onFailure(Throwable caught) {
				mEventBus.fireEvent(new FeedbackMessageEvent(caught
						.getMessage(), true));
			}
		});
	}

	/**
	 * Event Bus used to handle all communication between different parts of the
	 * module
	 */
	private final HandlerManager mEventBus;

	/**
	 * The linked display (widget)
	 */
	private Display mDisplay;
}
